#ifndef FIELD_H
#define FIELD_H

#include <time.h>
#include <stdlib.h>

#include "Object.h"
#include "Wall.h"
#include "Gangster.h"
#include "Graphics.h"
#include "Bullet.h"
#include "Shop.h"

enum GenerationType{ DEFAULT = 0, HUGEFIGHT, PATHFINDING };

  // game field, stores all objects
class Field
{
    public:
        static const int WIDTH  = 120;
        static const int HEIGHT = 120;

        static const char EMPTYSPACE = '.';

        Field( Graphics* dc, GenerationType type = DEFAULT )
        :graph(dc), currentUpdate(0), player(0),
        deathsOfRed(0), deathsOfGreen(0), deathsOfDemons(0),
        shop(new Shop(this))
        {
             generate( type );
        }

          // is called every time field updates
        void update();

        Graphics* getGraph() const { return graph; }
        void setGraph( Graphics* d ){ graph = d; }

        ~Field(){
            for( int i = 0; i < WIDTH; i++ ){
                for( int j = 0; j < HEIGHT; j++ ){
                    if( field[i][j] ) delete field[i][j];
                    field[i][j] = 0;
                }
            }
            delete shop;
        }

        void setPlayer( Mob* i ){ player = i;  }
        void addDeath( Team team );

        Mob* getPlayer() const{ return player; }
        Shop* getShop() const  { return shop; }
        int getDeathsOfRed() const { return deathsOfRed; }
        int getDeathsOfGreen() const { return deathsOfGreen; }
        int getDeathsOfDemons() const { return deathsOfDemons; }
        int getUpdate() const { return currentUpdate; }


          // saves field in file
        void saveInFile( const char* name, const char * name2 );
          // loads field from file
        void loadFromFile( const char* name, const char* name2 );
          // turns the field into empty spaces, fixed
        void clear();
          // random field generation
        void generate( GenerationType type = DEFAULT );

          // resurrects player at(x,y) if he is killed
          // destroys anything that is at(x,y) already
        void resurrectPlayer( int x, int y );

          // moves object in field to target location
        bool move( int x, int y, Object* o );
        bool move( Direction direction, int speed, Object* o );
          // deletes object in target location
        void destroy( int x, int y );
          // returns whatever is at target location
        Object* objectAt( int x, int y ) const;
        Object* objectAt( Direction d, int distance, Object* o );
        Object* objectAt( Direction d, int distance, int x, int y );
          // return coordinates of an objectAt ( used to find out coordinates of
          // empty spaces )
        int objectAtX(  Direction d, int distance, int x );
        int objectAtY(  Direction d, int distance, int y );
          // returns true if an enemy is in that direction
        bool enemyInDirection( Direction d, Mob* m );
          // returns true if a bullet is flying to a mob from that direction
        bool dangerInDirection( Direction d, Mob* m );
          // returns pointer to player if he is present, otherwise returns 0
        //Mob* getPlayer() const;
          // shifts mob, returns true in case of sucsess
        bool shift( Mob* m );
          // returns direction which points at an enemy which can be shot at
        Direction enemyInSight( Mob* m );
          // returns direction which points at a bullet which will or will not hit the mob
        Direction dangerInSight( Mob* m );
          // spawns object at target location, returns true if it is spawned, false if it doesn't
        bool spawnObject( int x, int y, Object* o );
        bool spawnObject( Direction d, int distance, Object* o );
          // returns true if object is in borders of field
        bool ifInBorders( int x, int y ) const;
    protected:
    private:
          // field itself here
        Object* field[WIDTH][HEIGHT];

          // stuff responsible for graphics
        Graphics* graph;

          // used to prevent acting several times per turn for
          // moving objects
        int currentUpdate;
          // is used to provide stats
        Mob* player;

          // for score
        int deathsOfRed;
        int deathsOfGreen;
        int deathsOfDemons;

          // in-game shop
        Shop* shop;

          // for shifting
        Mob* findShift( Mob* m );
        Mob* findShiftDirectional( Mob* m, Direction d );

        void shiftSwap( Mob* m, Mob* l );

          // random generator's functions
        void generateDefault();
        void generateHugeFight();
        void generatePathfindingTest();

        bool ifSpaceNearEdges( int i , int j ) const;
        bool ifSpaceNearEdgeWalls( int i, int j ) const;
        bool ifOuterCircle( int i, int j ) const;
        bool ifCircle( int i, int j, int x, int y ) const;
        bool ifLowerRightQuarter( int i, int j ) const;
        bool ifUpperLeftQuarter( int i, int j ) const;
        bool ifUpperRightQuarter( int i, int j ) const;
        bool ifLowerLeftQuarter( int i, int j ) const;
};

#endif // FIELD_H
